/*
 * Filename: server_tcp_epoll.c
 * Description: TODO: Add description
 *
 * Created: 2025-05-29
 * Author: lyh
 */

#include <my_header.h>

void quit(int *fd, int *epfd);

int main(int argc, char *argv[]) {
	// ./server_tcp_epoll 192.168.48.128 12345
	ARGS_CHECK(argc, 3);
	// 准备地址
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	server_addr.sin_port = htons(atoi(argv[2]));
	// 初始socket,绑定服务端端口
	int server_fd = socket(AF_INET, SOCK_STREAM, 0);
	ERROR_CHECK(server_fd, -1, "socket error");
	int tag = bind(server_fd, (struct sockaddr *)&server_addr,
				   sizeof(struct sockaddr_in));
	ERROR_CHECK(tag, -1, "bind error");
    listen(server_fd,10);

	// 设置epoll监听集合 fd epoll_event;
	int epfd = epoll_create(1);
	struct epoll_event add_fd_events, ready_fd_events;
	add_fd_events.data.fd = server_fd;
	add_fd_events.events = EPOLLIN;
	tag = epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &add_fd_events);
	ERROR_CHECK(tag, -1, "epoll_ctl error");

	// 用户先关数据
	int clinetfd=-1;
	char buffer[4096];
	while (1) {
		int maxcount = epoll_wait(epfd, &ready_fd_events, 1, -1);
		ERROR_CHECK(maxcount, -1, "epoll_wat error");
		ERROR_CHECK(maxcount, 0, "epoll_wait interrupt");
		if (ready_fd_events.data.fd == server_fd) {
			// 移除对server socket的监听,并将用户信息来源和客户端fd加入
			epoll_ctl(epfd, EPOLL_CTL_DEL, server_fd, NULL);

			clinetfd = accept(server_fd, NULL, NULL);
			ERROR_CHECK(clinetfd, -1, "accept error"); // 未清理资源

			add_fd_events.data.fd = clinetfd;
			epoll_ctl(epfd, EPOLL_CTL_ADD, clinetfd, &add_fd_events);

			add_fd_events.data.fd = STDIN_FILENO;
			epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &add_fd_events);
		} else {
				bzero(buffer, 4096);
			if (ready_fd_events.data.fd == clinetfd) {
                int read_count=recv(clinetfd,buffer,4096,0);
                if(read_count==0)
                {
                    add_fd_events.data.fd=STDIN_FILENO;
                    epoll_ctl(epfd,EPOLL_CTL_DEL,STDIN_FILENO,NULL);
                    add_fd_events.data.fd=server_fd;
                    epoll_ctl(epfd,EPOLL_CTL_ADD,server_fd,&add_fd_events);
                    printf("clinet %d: quit\n",clinetfd);
                    quit(&clinetfd,&epfd);
                    continue;
                }
                printf("client fd %d:%s\n",clinetfd,buffer);
			} else {
				int read_count = read(STDIN_FILENO, buffer, 4096);
				int tag = send(clinetfd, buffer, read_count, 0);
				if (tag == -1) {
					perror("send error");
					quit(&clinetfd, &epfd);
				}
			}
		}
	}
    quit(&clinetfd,&epfd);
    close(server_fd);
    close(epfd);
	return 0;
}

void quit(int *fd,int *epfd){
    if(*fd!=-1)
    {
        epoll_ctl(*epfd,EPOLL_CTL_DEL,*fd,NULL);
        close(*fd);
        *fd=-1;
    }
}
